<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>向量相似度搜索技术解析</title>
    <link href="https://cdn.staticfile.org/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
    <link href="https://cdn.staticfile.org/tailwindcss/2.2.19/tailwind.min.css" rel="stylesheet">
    <link href="https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;500;600;700&family=Noto+Sans+SC:wght@300;400;500;700&display=swap" rel="stylesheet">
    <script src="https://cdn.jsdelivr.net/npm/mermaid@latest/dist/mermaid.min.js"></script>
    <style>
        body {
            font-family: 'Noto Sans SC', 'Noto Serif SC', Tahoma, Arial, Roboto, "Droid Sans", "Helvetica Neue", "Droid Sans Fallback", "Heiti SC", "Hiragino Sans GB", Simsun, sans-serif;
            background-color: #f9fafb;
            color: #1f2937;
            line-height: 1.6;
        }
        .hero-gradient {
            background: linear-gradient(135deg, #6b21a8 0%, #9333ea 50%, #c084fc 100%);
        }
        .code-block {
            background-color: #1e293b;
            color: #f8fafc;
            border-radius: 0.5rem;
            overflow: hidden;
        }
        .code-header {
            background-color: #334155;
            padding: 0.5rem 1rem;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        .method-tag {
            background-color: rgba(167, 139, 250, 0.3);
            border: 1px solid #8b5cf6;
        }
        .param-tag {
            background-color: rgba(74, 222, 128, 0.3);
            border: 1px solid #10b981;
        }
        .return-tag {
            background-color: rgba(96, 165, 250, 0.3);
            border: 1px solid #3b82f6;
        }
        .card-hover:hover {
            transform: translateY(-4px);
            box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
        }
        .section-divider {
            height: 1px;
            background: linear-gradient(90deg, transparent, #a78bfa, transparent);
        }
    </style>
</head>
<body class="min-h-screen">
    <!-- Hero Section -->
    <section class="hero-gradient text-white py-20 px-6">
        <div class="max-w-6xl mx-auto">
            <div class="flex flex-col md:flex-row items-center">
                <div class="md:w-1/2 mb-10 md:mb-0">
                    <h1 class="text-4xl md:text-5xl font-bold mb-4 leading-tight">向量相似度搜索</h1>
                    <p class="text-xl opacity-90 mb-8">高效处理高维数据相似性检索的核心算法与技术</p>
                    <div class="flex flex-wrap gap-3">
                        <span class="px-4 py-2 bg-white bg-opacity-20 rounded-full">机器学习</span>
                        <span class="px-4 py-2 bg-white bg-opacity-20 rounded-full">信息检索</span>
                        <span class="px-4 py-2 bg-white bg-opacity-20 rounded-full">高维数据</span>
                    </div>
                </div>
                <div class="md:w-1/2 flex justify-center">
                    <div class="w-full max-w-md">
                        <div class="mermaid">
                            graph TD
                            A[查询向量] --> B[相似度计算]
                            B --> C[KD树搜索]
                            B --> D[LSH哈希]
                            C --> E[最近邻结果]
                            D --> E
                            E --> F[排名输出]
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </section>

    <!-- Main Content -->
    <div class="max-w-6xl mx-auto px-6 py-12">
        <!-- Problem Definition -->
        <section class="mb-16">
            <div class="flex items-center mb-8">
                <div class="w-12 h-12 rounded-full bg-purple-100 flex items-center justify-center mr-4">
                    <i class="fas fa-question text-purple-600 text-xl"></i>
                </div>
                <h2 class="text-3xl font-bold">问题描述</h2>
            </div>
            <div class="bg-white rounded-xl shadow-md p-8">
                <p class="text-lg leading-relaxed mb-6">
                    给定一组高维向量和一个查询向量，如何高效地在数据集中查找与查询向量最相似的向量？这是信息检索、推荐系统和机器学习中的核心问题。随着数据维度的增加，传统的线性搜索方法变得不可行，需要更高效的近似最近邻搜索算法。
                </p>
                <div class="bg-blue-50 border-l-4 border-blue-500 p-4 rounded-r">
                    <p class="text-blue-800"><i class="fas fa-info-circle mr-2"></i>实际应用场景包括：图像检索、文档相似性匹配、推荐系统、异常检测等</p>
                </div>
            </div>
        </section>

        <!-- Algorithm Overview -->
        <section class="mb-16">
            <div class="flex items-center mb-8">
                <div class="w-12 h-12 rounded-full bg-indigo-100 flex items-center justify-center mr-4">
                    <i class="fas fa-project-diagram text-indigo-600 text-xl"></i>
                </div>
                <h2 class="text-3xl font-bold">核心算法解析</h2>
            </div>
            
            <div class="grid md:grid-cols-2 gap-8 mb-10">
                <!-- KD Tree Card -->
                <div class="bg-white rounded-xl shadow-md overflow-hidden card-hover transition-all duration-300">
                    <div class="bg-gradient-to-r from-purple-600 to-indigo-600 p-4 text-white">
                        <h3 class="text-xl font-bold flex items-center">
                            <i class="fas fa-tree mr-3"></i>KD 树算法
                        </h3>
                    </div>
                    <div class="p-6">
                        <p class="mb-4">构建多维空间的二叉树，通过递归划分空间来优化最近邻搜索。</p>
                        <ul class="space-y-2 mb-6">
                            <li class="flex items-start">
                                <i class="fas fa-check-circle text-green-500 mt-1 mr-2"></i>
                                <span>时间复杂度：O(log n)（平均情况）</span>
                            </li>
                            <li class="flex items-start">
                                <i class="fas fa-check-circle text-green-500 mt-1 mr-2"></i>
                                <span>空间复杂度：O(n)</span>
                            </li>
                            <li class="flex items-start">
                                <i class="fas fa-check-circle text-green-500 mt-1 mr-2"></i>
                                <span>适合中等维度的数据</span>
                            </li>
                        </ul>
                        <div class="bg-gray-100 p-3 rounded-lg">
                            <p class="text-sm text-gray-700"><i class="fas fa-lightbulb mr-2"></i>通过空间划分减少需要比较的向量数量，避免全量计算</p>
                        </div>
                    </div>
                </div>
                
                <!-- LSH Card -->
                <div class="bg-white rounded-xl shadow-md overflow-hidden card-hover transition-all duration-300">
                    <div class="bg-gradient-to-r from-blue-600 to-cyan-600 p-4 text-white">
                        <h3 class="text-xl font-bold flex items-center">
                            <i class="fas fa-fingerprint mr-3"></i>局部敏感哈希 (LSH)
                        </h3>
                    </div>
                    <div class="p-6">
                        <p class="mb-4">通过哈希函数将相近向量映射到相同桶，实现近似最近邻搜索。</p>
                        <ul class="space-y-2 mb-6">
                            <li class="flex items-start">
                                <i class="fas fa-check-circle text-green-500 mt-1 mr-2"></i>
                                <span>时间复杂度：O(1)（近似）</span>
                            </li>
                            <li class="flex items-start">
                                <i class="fas fa-check-circle text-green-500 mt-1 mr-2"></i>
                                <span>空间复杂度：O(n)</span>
                            </li>
                            <li class="flex items-start">
                                <i class="fas fa-check-circle text-green-500 mt-1 mr-2"></i>
                                <span>适合高维数据</span>
                            </li>
                        </ul>
                        <div class="bg-gray-100 p-3 rounded-lg">
                            <p class="text-sm text-gray-700"><i class="fas fa-lightbulb mr-2"></i>牺牲少量精度换取速度，适用于大规模高维数据</p>
                        </div>
                    </div>
                </div>
            </div>
            
            <div class="bg-white rounded-xl shadow-md overflow-hidden">
                <div class="p-6">
                    <div class="mermaid">
                        graph LR
                        A[输入向量] --> B[选择算法]
                        B -->|低维度| C[KD树]
                        B -->|高维度| D[LSH]
                        C --> E[精确搜索]
                        D --> F[近似搜索]
                        E --> G[返回结果]
                        F --> G
                    </div>
                </div>
            </div>
        </section>

        <!-- Code Implementation -->
        <section class="mb-16">
            <div class="flex items-center mb-8">
                <div class="w-12 h-12 rounded-full bg-emerald-100 flex items-center justify-center mr-4">
                    <i class="fas fa-code text-emerald-600 text-xl"></i>
                </div>
                <h2 class="text-3xl font-bold">代码实现</h2>
            </div>
            
            <div class="mb-10">
                <h3 class="text-2xl font-semibold mb-6 text-gray-800 flex items-center">
                    <i class="fas fa-calculator mr-3 text-purple-600"></i>
                    余弦相似度计算
                </h3>
                <div class="code-block">
                    <div class="code-header">
                        <span class="text-sm text-gray-300">VectorSimilaritySearch.java</span>
                        <span class="px-2 py-1 bg-purple-600 rounded text-xs">核心方法</span>
                    </div>
                    <pre class="p-4 overflow-x-auto"><code class="text-sm">/**
 * 计算两个向量之间的余弦相似度
 * 余弦相似度 = 向量点积 / (向量1范数 * 向量2范数)
 * 
 * @param vec1 第一个向量
 * @param vec2 第二个向量
 * @return 两个向量的余弦相似度，范围[-1,1]，值越大表示越相似
 */
public static double cosineSimilarity(double[] vec1, double[] vec2) {
    // 确保两个向量长度相同
    if (vec1.length != vec2.length) {
        throw new IllegalArgumentException("向量维度不匹配");
    }
    
    // 计算点积
    double dotProduct = 0.0;
    for (int i = 0; i < vec1.length; i++) {
        dotProduct += vec1[i] * vec2[i];
    }
    
    // 计算向量范数
    double norm1 = 0.0;
    double norm2 = 0.0;
    for (int i = 0; i < vec1.length; i++) {
        norm1 += vec1[i] * vec1[i];
        norm2 += vec2[i] * vec2[i];
    }
    norm1 = Math.sqrt(norm1);
    norm2 = Math.sqrt(norm2);
    
    // 避免除以零
    if (norm1 == 0.0 || norm2 == 0.0) {
        return 0.0;
    }
    
    // 返回余弦相似度
    return dotProduct / (norm1 * norm2);
}</code></pre>
                </div>
            </div>
            
            <div class="grid md:grid-cols-2 gap-8 mb-10">
                <!-- KD Tree Implementation -->
                <div>
                    <h3 class="text-2xl font-semibold mb-6 text-gray-800 flex items-center">
                        <i class="fas fa-tree mr-3 text-indigo-600"></i>
                        KD树实现
                    </h3>
                    <div class="code-block h-full">
                        <div class="code-header">
                            <span class="text-sm text-gray-300">KDNode.java</span>
                            <span class="px-2 py-1 bg-indigo-600 rounded text-xs">数据结构</span>
                        </div>
                        <pre class="p-4 overflow-x-auto"><code class="text-sm">/**
 * KD树节点类
 */
static class KDNode {
    double[] point;
    int axis;
    KDNode left;
    KDNode right;
    
    public KDNode(double[] point, int axis) {
        this.point = point;
        this.axis = axis;
    }
}

/**
 * 构建KD树
 * 
 * @param points 点集合
 * @param depth 当前深度
 * @param k 维度
 * @return KD树根节点
 */
public static KDNode buildKDTree(List&lt;double[]&gt; points, int depth, int k) {
    if (points.isEmpty()) {
        return null;
    }
    
    // 选择划分维度
    int axis = depth % k;
    
    // 按当前维度排序点
    int medianIdx = points.size() / 2;
    points.sort(Comparator.comparingDouble(point -> point[axis]));
    
    // 创建节点
    KDNode node = new KDNode(points.get(medianIdx), axis);
    
    // 递归构建左右子树
    node.left = buildKDTree(points.subList(0, medianIdx), depth + 1, k);
    node.right = buildKDTree(points.subList(medianIdx + 1, points.size()), depth + 1, k);
    
    return node;
}</code></pre>
                    </div>
                </div>
                
                <!-- Similarity Search -->
                <div>
                    <h3 class="text-2xl font-semibold mb-6 text-gray-800 flex items-center">
                        <i class="fas fa-search mr-3 text-blue-600"></i>
                        相似向量搜索
                    </h3>
                    <div class="code-block h-full">
                        <div class="code-header">
                            <span class="text-sm text-gray-300">VectorSimilaritySearch.java</span>
                            <span class="px-2 py-1 bg-blue-600 rounded text-xs">搜索算法</span>
                        </div>
                        <pre class="p-4 overflow-x-auto"><code class="text-sm">/**
 * 在向量集合中查找与查询向量最相似的k个向量
 * 
 * @param vectors 向量集合
 * @param query 查询向量
 * @param k 返回的最相似向量数量
 * @return 最相似的k个向量的索引列表
 */
public static List&lt;Integer&gt; findMostSimilar(List&lt;double[]&gt; vectors, double[] query, int k) {
    // 存储每个向量的索引及其与查询向量的相似度
    PriorityQueue&lt;Map.Entry&lt;Integer, Double&gt;&gt; pq = new PriorityQueue&lt;&gt;(
            (a, b) -> Double.compare(a.getValue(), b.getValue()));
    
    // 计算每个向量与查询向量的相似度
    for (int i = 0; i &lt; vectors.size(); i++) {
        double similarity = cosineSimilarity(vectors.get(i), query);
        
        // 维护大小为k的优先队列
        if (pq.size() &lt; k) {
            pq.offer(new AbstractMap.SimpleEntry&lt;&gt;(i, similarity));
        } else if (similarity &gt; pq.peek().getValue()) {
            pq.poll();
            pq.offer(new AbstractMap.SimpleEntry&lt;&gt;(i, similarity));
        }
    }
    
    // 按相似度从高到低排序结果
    List&lt;Integer&gt; result = new ArrayList&lt;&gt;();
    while (!pq.isEmpty()) {
        result.add(0, pq.poll().getKey());
    }
    
    return result;
}</code></pre>
                    </div>
                </div>
            </div>
        </section>

        <!-- Performance Comparison -->
        <section>
            <div class="flex items-center mb-8">
                <div class="w-12 h-12 rounded-full bg-amber-100 flex items-center justify-center mr-4">
                    <i class="fas fa-tachometer-alt text-amber-600 text-xl"></i>
                </div>
                <h2 class="text-3xl font-bold">性能对比</h2>
            </div>
            
            <div class="bg-white rounded-xl shadow-md p-8">
                <div class="overflow-x-auto">
                    <table class="min-w-full divide-y divide-gray-200">
                        <thead class="bg-gray-50">
                            <tr>
                                <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">算法</th>
                                <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">时间复杂度</th>
                                <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">空间复杂度</th>
                                <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">精度</th>
                                <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">适用场景</th>
                            </tr>
                        </thead>
                        <tbody class="bg-white divide-y divide-gray-200">
                            <tr>
                                <td class="px-6 py-4 whitespace-nowrap font-medium text-purple-600">KD树</td>
                                <td class="px-6 py-4 whitespace-nowrap">O(log n)</td>
                                <td class="px-6 py-4 whitespace-nowrap">O(n)</td>
                                <td class="px-6 py-4 whitespace-nowrap">精确</td>
                                <td class="px-6 py-4 whitespace-nowrap">低至中等维度</td>
                            </tr>
                            <tr>
                                <td class="px-6 py-4 whitespace-nowrap font-medium text-blue-600">LSH</td>
                                <td class="px-6 py-4 whitespace-nowrap">O(1)</td>
                                <td class="px-6 py-4 whitespace-nowrap">O(n)</td>
                                <td class="px-6 py-4 whitespace-nowrap">近似</td>
                                <td class="px-6 py-4 whitespace-nowrap">高维度大数据</td>
                            </tr>
                            <tr>
                                <td class="px-6 py-4 whitespace-nowrap font-medium text-gray-600">线性搜索</td>
                                <td class="px-6 py-4 whitespace-nowrap">O(n)</td>
                                <td class="px-6 py-4 whitespace-nowrap">O(1)</td>
                                <td class="px-6 py-4 whitespace-nowrap">精确</td>
                                <td class="px-6 py-4 whitespace-nowrap">小数据集</td>
                            </tr>
                        </tbody>
                    </table>
                </div>
                
                <div class="mt-8">
                    <div class="mermaid">
                        barChart
                            title 算法性能对比
                            x-axis 算法
                            y-axis 时间(对数刻度)
                            bar "KD树" : 1
                            bar "LSH" : 0.5
                            bar "线性搜索" : 10
                    </div>
                </div>
            </div>
        </section>
    </div>

    <script>
        mermaid.initialize({
            startOnLoad: true,
            theme: 'default',
            flowchart: {
                useMaxWidth: true,
                htmlLabels: true,
                curve: 'basis'
            },
            themeVariables: {
                primaryColor: '#8b5cf6',
                primaryTextColor: '#fff',
                primaryBorderColor: '#7c3aed',
                lineColor: '#a78bfa',
                secondaryColor: '#d8b4fe',
                tertiaryColor: '#ede9fe'
            }
        });
    </script>
</body>
</html>